package com.spark.sniffer.plugin.plugins.interceptor;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.spark.sniffer.AgentArgs;
import com.spark.sniffer.logging.api.Logger;
import com.spark.sniffer.logging.api.LoggerFactory;
import com.spark.sniffer.plugin.interceptor.StaticMethodsAroundInterceptor;
import com.spark.sniffer.plugin.interceptor.enhance.MethodInterceptResult;
import com.spark.sniffer.tracing.Span;
import com.spark.sniffer.tracing.TracingContext;

public class HttpUtilsInterceptor implements StaticMethodsAroundInterceptor {
    private static final Logger log = LoggerFactory.getLogger(HttpUtilsInterceptor.class);

    @Override
    public void beforeMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
        MethodInterceptResult result) {
        // 数据透传处理
        passThroughs(allArguments, parameterTypes);

        if (TracingContext.getContext().getEntrance() == null) {
            return;
        }

        TracingContext.getContext().startSpan(Span.Type.HttpClient,
            AgentArgs.isSimpleTracing() ? null : (method.getName() + "<" + allArguments[0] + ">"));

    }

    @Override
    public Object afterMethod(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
        Object ret) {
        if (TracingContext.getContext().getEntrance() == null) {
            return ret;
        }

        TracingContext.getContext().stopSpan();
        return ret;
    }

    @Override
    public void handleMethodException(Class clazz, Method method, Object[] allArguments, Class<?>[] parameterTypes,
        Throwable t) {
        TracingContext.getContext().setActiveSpanCode(Span.ERR_CODE);
    }

    /**
     * @param allArguments
     * @param parameterTypes
     */
    private void passThroughs(Object[] allArguments, Class<?>[] parameterTypes) {
        // 将traceid/X-User-Agent/abtest_group通过http header向下游系统进行透传
        for (int i = 0; i < parameterTypes.length; i++) {
            // Map参数就是header了（没有其他标识，只能通过Map类型进行判断，注意如果HttpUtils有人传了其他参数为Map类型，那就67了）
            if (parameterTypes[i] != null && parameterTypes[i].isAssignableFrom(Map.class)) {
                @SuppressWarnings("unchecked")
                Map<String, String> headers = (Map<String, String>)allArguments[i];
                if (headers == null) {
                    headers = new HashMap<>();
                    allArguments[i] = headers;
                }

                // 设置透传数据
                Map<String, String> passThroughMap = TracingContext.getContext().getPassThroughMap();
                if (passThroughMap != null) {
                    for (Entry<String, String> x : passThroughMap.entrySet()) {
                        headers.put(x.getKey(), x.getValue());
                        log.debug("pass through HttpUtils header, {}={}", x.getKey(), x.getValue());
                    }
                }

                break;
            }
        }
    }
}
